package dbLink

import (
	"fmt"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"strings"
	"sync"
)

// 初始化配置,init函数，导入这个包时会自动执行
func init() {
	fmt.Println("执行初始化")
	//设置默认值
	viper.SetDefault("user", "root")
	viper.SetDefault("dbname", "tiktok_mall")
	//输出默认配置
	fmt.Printf("user:%v\n", viper.Get("user"))
	fmt.Printf("dbname:%v\n", viper.Get("dbname"))

	//TODO：路径还是在go.mod那里开始算！
	viper.SetConfigFile("./application.yaml") // 指定配置文件路径
	viper.SetConfigName("application")        // 配置文件名称(无扩展名)
	viper.SetConfigType("yaml")               // 如果配置文件的名称中没有扩展名，则需要配置此项
	viper.AddConfigPath(".")                  // 指定在那里找配置文件，可以写多个路径。这里“.”代表在工作目录中查找配置
	err := viper.ReadInConfig()               // 查找并读取配置文件
	if err != nil {                           // 处理读取配置文件的错误
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	//TODO:yml文件又缩进的通过下面的方式.读取配置
	fmt.Printf("host:%v\n", viper.Get("mysql.host"))
}

/*
sync.Once 是 Go 语言中的一个类型，用于确保某个操作只执行一次。它提供了一个 Do 方法，该方法接受一个函数作为参数，
并保证该函数在程序的生命周期中只执行一次，即使在多线程环境下也是如此。  在你的代码中，once sync.Once 定义了
一个 sync.Once 类型的变量 once，然后在 GetDB 函数中使用 once.Do 来确保数据库连接只被初始化一次。
*/
var (
	db   *gorm.DB
	once sync.Once
)

func GetDB() *gorm.DB {
	/*
		TODO：这里传给他的是匿名函数
		once.Do方法确保传入的函数只会被执行一次，即使在多线程环境下也是如此。因此，数据库连接池的初始化只会执行一次。
		如果 once.Do 已经执行过，那么后续调用 GetDB 方法时，once.Do 内的代码不会再执行，直接返回已经初始化的 db 对象。
	*/
	once.Do(func() {
		var err error
		user := viper.GetString("mysql.user")
		password := viper.GetString("mysql.password")
		host := viper.GetString("mysql.host")
		dbname := viper.GetString("mysql.dbname")
		port := viper.GetString("mysql.port")
		var sb strings.Builder
		sb.WriteString(user + ":" + password + "@tcp(" + host + ":" + port + ")/" + dbname + "?charset=utf8mb4&parseTime=True&loc=Local")
		//dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
		dsn := sb.String()
		fmt.Println(dsn)
		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
		if err != nil {
			log.Fatalf("Failed to connect to database: %v", err)
		}
		sqlDB, err := db.DB()
		if err != nil {
			log.Fatalf("Failed to get database instance: %v", err)
		}
		// Set connection pool settings
		sqlDB.SetMaxOpenConns(25)
		sqlDB.SetMaxIdleConns(25)
		sqlDB.SetConnMaxLifetime(5 * 60)
	})
	return db
}
